---------Audubon Grizzly Bears---------
----------Wildlife Adventures----------
A 4am crack                  2016-02-01
---------------------------------------

Name: Audubon Grizzly Bears: Wildlife
  Adventures
Genre: educational
Year: 1988
Executive Producer: Christopher Palmer
Producer & Director: Dennis Sullivan
Writing: Deborah Kovacs, Pat Relf
Programming: Drew Ruscil, Dennis
  Sullivan
Art & Music: The Dovetail Group, Inc.
  Gerri Brioso, Cynthia Vansant,
  Richard Frietas, Paul Frietas
Biological Illustration: Doreen Curtin
Research & Testing: Andy Henriquez
Documentation: Roger DiSilvestro,
  Richard Chevat, Sandy Damashek,
  Susan Greer, Jeffrey Siegel
Conceived & Produced by National
  Audubon Society
Publisher: Advanced Ideas, Inc.
Media: 5 single-sided 5.25-inch disks
OS: ProDOS 1.5
Previous cracks: none
Similar cracks:
  #339 SuperPrint
  #146 Math Shop
  #047 Deathsword

Disk 1 is protected and bootable.
Disks 2-5 are unprotected but
unbootable.
Life is like that.
This has not been a haiku.

                   ~

               Chapter 0
 In Which Various Automated Tools Fail
          In Interesting Ways


COPYA
  immediate disk read error

Locksmith Fast Disk Backup
  unable to read any track

EDD 4 bit copy (no sync, no count)
  no errors, but copy reboots endlessly

Copy ][+ nibble editor
  standard prologues
  (address: D5 AA 96, data: D5 AA AD)
  modified epilogues
  (address: FF FF FF, data: FF FF FF)

Disk Fixer
  ["O" -> "Input/Output Control"]
    set CHECKSUM ENABLED to "NO"
  Success!
  T00 -> looks like ProDOS bootloader
    and disk catalog (volume name is
    "GRIZZLYBEARS")

Why didn't COPYA work?
  modified epilogue bytes (every track)

Why didn't Locksmith FDB work?
  modified epilogue bytes (every track)

Why didn't my EDD copy work?
  Probably a nibble check during boot.
  In my experience, computers do not
  spontaneously reboot unless someone
  tells them to.

Next steps:

  1. Super Demuffin to convert disk to
     standard format
  2. patch RWTS to read standard format
     (if necessary)
  3. find nibble check and disable it

                   ~

               Chapter 1
       In Which We Try To Choose
      The Right Tool For The Job,
        And It Fails Miserably


My AUTOTRACE script doesn't do much for
me on ProDOS disks, but it looks like
every track has the same prologues and
epilogues, so I'm going to convert it
with Super Demuffin.

When you first run Super Demuffin, it
asks for the parameters of the original
disk. In this case, the prologue bytes
are the same, but the epilogues are "FF
FF FF" instead of "DE AA EB".

                 --v--

      SUPER-DEMUFFIN AND FAST COPY
Modified by: The Saltine/Coast to Coast


   Address prologue: D5 AA 96

   Address epilogue: FF FF FF    DISK
                     ^^^^^^^^  ORIGINAL
             *change from "DE AA EB"

      Data prologue: D5 AA AD

      Data epilogue: FF FF FF
                     ^^^^^^^^
             *change from "DE AA EB"


 Ignore write errors while demuffining!


  D - Edit parameters
      <SPACE> - Advance to next parm
      <RETURN> - Exit edit mode
  R - Restore DOS 3.3 parameters
  O - Edit Original disk's parameters
  C - Edit Copy disk's parameters
  G - Begin demuffin process

                 --^--

Pressing "G" switches to the Locksmith
Fast Disk Copy UI. It assumes that both
disks are in slot 6, and that drive 1
is the original and drive 2 is the
copy, so let's do that.

[S6,D1=original disk]
[S6,D2=blank disk]

                 --v--

     LOCKSMITH 7.0  FAST DISK BACKUP


   R*..............**..................
   W***********************************
HEX 00000000000000001111111111111111222
TRK 0123456789ABCDEF0123456789ABCDEF012
   0................D..................
   1...............D...................
   2...............D...................
   3...............D...................
   4...............D...................
   5...............D...................
   6...................................
   7...................................
   8D..............D...................
   9D..............D...................
   AD...............D..................
   BD...............D..................
   C................D..................
   D...................................
12 E................D..................
   F...............D...................
[               ] PRESS [RESET] TO EXIT

                 --^--

That's... odd. Revisiting the original
disk in my trusty Disk Fixer sector
editor, I discover the problem: those
"unreadable" sectors are actually in a
standard format. That is, they use the
normal "DE AA EB" epilogues instead of
the non-standard "FF FF FF" epilogues
that all the other sectors use.

I suspect the RWTS on disk is flexible
about epilogues when it reads, but it
always uses standard epilogues when it
writes. It started out all uniform, but
at some point it made some changes to
one or more files, which wrote out
standard sectors on tracks $0F/$10,
plus the disk catalog on track $00.

But I'm going to trace the boot to make
sure, before I make any more
assumptions.

                   ~

               Chapter 2
    In Which We Do It The Hard Way,
            And Explain Why


[S6,D1=original disk]
[S5,D1=my work disk]

]PR#5
CAPTURING BOOT0
...reboots slot 6...
...reboots slot 5...
SAVING BOOT0

As I said, my AUTOTRACE script doesn't
get very far tracing ProDOS (note to
self: fix that someday), but the boot
sector looks like a fairly standard
ProDOS bootloader. I can trap it at
$08FC to capture the PRODOS file in
memory.

]CALL -151

*9600<C600.C6FFM

; ProDOS boot is sensitive to the value
; in the accumulator, so let's not lose
; track of that
96F8-   48          PHA

; set up callback after PRODOS file is
; in memory
96F9-   A9 4C       LDA   #$4C
96FB-   8D FC 08    STA   $08FC
96FE-   A9 0C       LDA   #$0C
9700-   8D FD 08    STA   $08FD
9703-   A9 97       LDA   #$97
9705-   8D FE 08    STA   $08FE

; restore accumulator & start the boot
9708-   68          PLA
9709-   4C 01 08    JMP   $0801

; callback is here --
; turn off slot 6 drive motor and
; reboot to my work disk
970C-   AD E8 C0    LDA   $C0E8
970F-   4C 00 C5    JMP   $C500

*BSAVE TRACE,A$9600,L$112

; wipe main memory with an unusual byte
; so I can see how long the PRODOS file
; is later
*800:FD N 801<800.95FEM

; and start the trace
*9600G
...reboots slot 6...
...read read read...
...reboots slot 5...

]CALL -151

*2000L
.
.
.

The PRODOS file is loaded at $2000. The
first page after $2000 that still has
repeating $FD bytes is $5E00.

*5E-20
=3E
*BSAVE OBJ.PRODOS,A$2000,A$3E00

In most versions of ProDOS, the RWTS
code starts at $xx98, where "xx" varies
between $53 and $56. (ASK ME HOW I KNOW
THIS.) And true to form, I found it on
this disk at $5598.

*5598L

5598-   A0 FC       LDY   #$FC
559A-   8C 6B D3    STY   $D36B
559D-   C8          INY
559E-   D0 05       BNE   $55A5
55A0-   EE 6B D3    INC   $D36B
55A3-   F0 56       BEQ   $55FB

; match address prologue (D5 AA 96)
55A5-   BD 8C C0    LDA   $C08C,X
55A8-   10 FB       BPL   $55A5
55AA-   C9 D5       CMP   #$D5
55AC-   D0 EF       BNE   $559D
55AE-   EA          NOP
55AF-   BD 8C C0    LDA   $C08C,X
55B2-   10 FB       BPL   $55AF
55B4-   C9 AA       CMP   #$AA
55B6-   D0 F2       BNE   $55AA
55B8-   A0 03       LDY   #$03
55BA-   BD 8C C0    LDA   $C08C,X
55BD-   10 FB       BPL   $55BA
55BF-   C9 96       CMP   #$96
55C1-   D0 E7       BNE   $55AA
...

; now match address epilogue
55E6-   BD 8C C0    LDA   $C08C,X
55E9-   10 FB       BPL   $55E6
55EB-   C9 DE       CMP   #$DE
55ED-   90 0C       BCC   $55FB   <-- !
55EF-   EA          NOP
55F0-   BD 8C C0    LDA   $C08C,X
55F3-   10 FB       BPL   $55F0
55F5-   C9 AA       CMP   #$AA
55F7-   90 02       BCC   $55FB   <-- !
55F9-   18          CLC
55FA-   60          RTS
55FB-   38          SEC
55FC-   60          RTS

Aha! I was right. This RWTS has been
modified to accept epilogue bytes of
"DE AA" or higher (either or both).
That explains why it can read disk 1,
which uses "FF FF", but also read disks
2-5, which use the standard "DE AA".

To convert this disk entirely to a
standard format, I need a similarly
tolerant RWTS.

[S6,D1=DOS 3.3 master disk]

*C600G
...

]CALL -151

*3800<B800.BFFFM
*3936:90
*3940:B0
*3992:90
*399C:90
*BSAVE RWTS BCC,A$3800,L$800,S5,D2

Now I'll explain what the hell I just
did, and why.

To convert this disk, I need to use
Advanced Demuffin, which takes a DOS-
3.3-shaped RWTS. So, I rebooted to the
DOS 3.3 system master disk to get its
RWTS in memory. Then I made a copy at
$3800. Then I made four patches:

*392FL

; match data epilogue
392F-   BD 8C C0    LDA   $C08C,X
3932-   10 FB       BPL   $392F
3934-   C9 DE       CMP   #$DE
3936-   90 0A       BCC   $3942   <-- 1
3938-   EA          NOP
3939-   BD 8C C0    LDA   $C08C,X
393C-   10 FB       BPL   $3939
393E-   C9 AA       CMP   #$AA    <-- 2
3940-   B0 5C       BCS   $399E
3942-   38          SEC
3943-   60          RTS

*398BL

; match address epilogue
398B-   BD 8C C0    LDA   $C08C,X
398E-   10 FB       BPL   $398B
3990-   C9 DE       CMP   #$DE
3992-   90 AE       BCC   $3942   <-- 3
3994-   EA          NOP
3995-   BD 8C C0    LDA   $C08C,X
3998-   10 FB       BPL   $3995
399A-   C9 AA       CMP   #$AA
399C-   90 A4       BCC   $3942   <-- 4
399E-   18          CLC
399F-   60          RTS

In combination, these four patches turn
the normal DOS 3.3 RWTS into a tolerant
RWTS that matches the one used by the
PRODOS file on the original disk.

Now I can plug this RWTS file into
Advanced Demuffin and convert the disk,
with its weird combination of standard
and non-standard sectors, in one shot.

Why not use the old B942:18 trick to
disable RWTS error checking completely?
  This method is safer, because the
  resulting RWTS still verifies the
  checksums of the address field and
  the data field. If there really is a
  bad sector on my original disk (not a
  theoretical concern with 30-year-old
  floppies), I won't blast through it
  without noticing.

                   ~

               Chapter 3
 In Which We Use, Well, Not Quite The
   Original Disk Against Itself, But
 Something Approximating The Original


[S6,D1=original disk]
[S6,D2=blank disk]
[S5,D1=my work disk]

]PR#5
]BRUN ADVANCED DEMUFFIN 1.5

[press "5" to switch to slot 5]

[press "R" to load a new RWTS module]
  --> At $B8, load "RWTS BCC,D1"

[press "6" to switch to slot 6]

[press "C" to convert disk]

                 --v--

ADVANCED DEMUFFIN 1.5    (C) 1983, 2014
ORIGINAL BY THE STACK    UPDATES BY 4AM
=======PRESS ANY KEY TO CONTINUE=======
TRK:...................................
+.5:
    0123456789ABCDEF0123456789ABCDEF012
SC0:...................................
SC1:...................................
SC2:...................................
SC3:...................................
SC4:...................................
SC5:...................................
SC6:...................................
SC7:...................................
SC8:...................................
SC9:...................................
SCA:...................................
SCB:...................................
SCC:...................................
SCD:...................................
SCE:...................................
SCF:...................................
=======================================
16SC $00,$00-$22,$0F BY1.0 S6,D1->S6,D2

                 --^--

Whew. That was a lot of work, but it
was worth it to ensure that the
conversion is clean and the original
disk is free of bad sectors.

]PR#6
...reboots endlessly...

Now the real fun begins.

                   ~

               Chapter 4
  In Which We Run Into An Old Friend


Let's take another look at that
"standard" bootloader I captured.

[S6,D1=original disk]
[S5,D1=my work disk]

]PR#5
]BLOAD BOOT0,A$800
]CALL -151

*801L

; This looks like the standard ProDOS
; boot0 code, which is unsurprising,
; since the original disk loads ProDOS
0801-   38          SEC
0802-   B0 03       BCS   $0807
0804-   4C 32 A1    JMP   $A132
0807-   86 43       STX   $43
0809-   C9 03       CMP   #$03
080B-   08          PHP
080C-   8A          TXA
080D-   29 70       AND   #$70
080F-   4A          LSR
0810-   4A          LSR
0811-   4A          LSR
0812-   4A          LSR
0813-   09 C0       ORA   #$C0
0815-   85 49       STA   $49
0817-   A0 FF       LDY   #$FF
0819-   84 48       STY   $48
081B-   28          PLP
081C-   C8          INY
081D-   B1 48       LDA   ($48),Y
081F-   D0 3A       BNE   $085B
0821-   B0 0E       BCS   $0831
0823-   A9 03       LDA   #$03
0825-   8D 00 08    STA   $0800
0828-   E6 3D       INC   $3D
082A-   A5 49       LDA   $49
082C-   48          PHA
082D-   A9 5B       LDA   #$5B
082F-   48          PHA
0830-   60          RTS

; hey now, this is not standard
0831-   4C 00 09    JMP   $0900

Let's see what's lurking at $0900. To
do this, I'll need to interrupt the
boot process at $0831, after the code
is loaded into memory but before it
gets executed.

*9600<C600.C6FFM

; ProDOS boot0 code is sensitive to the
; value of the accumulator on entry, so
; make sure we save it and restore it
96F8-   48          PHA

; set up callback to call a routine
; under my control instead of
; continuing to $0900
96F9-   A9 07       LDA   #$07
96FB-   8D 32 08    STA   $0832
96FE-   A9 97       LDA   #$97
9700-   8D 33 08    STA   $0833

; restore the accumulator
9703-   68          PLA

; start the boot
9704-   4C 01 08    JMP   $0801

; callback is here -- relocate the code
; at $0900 to the graphics page so it
; will survive a reboot (my work disk
; auto-loads a HELLO program that would
; overwrite it at $0900)
9707-   A0 00       LDY   #$00
9709-   B9 00 09    LDA   $0900,Y
970C-   99 00 29    STA   $2900,Y
970F-   C8          INY
9710-   D0 F7       BNE   $9709

; turn off the slot 6 drive motor
9712-   AD E8 C0    LDA   $C0E8

; reboot to my work disk
9715-   4C 00 C5    JMP   $C500

*BSAVE TRACE1,A$9600,L$118
*9600G
...reboots slot 6...
...reboots slot 5...

]BSAVE BOOT1 0900-09FF,A$2900,L$100
]CALL -151

*900<2900.29FFM
*900L

; the first few instructions here are
; what usually happen at $0831 (instead
; of jumping to $0900)
0900-   85 48       STA   $48
0902-   85 40       STA   $40

; munge reset vector
0904-   A9 00       LDA   #$00
0906-   8D F4 03    STA   $03F4

; a counter?
0909-   A9 0A       LDA   #$0A
090B-   85 F4       STA   $F4

; turning on the drive motor manually
; (highly suspicious)
090D-   A6 2B       LDX   $2B
090F-   BD 89 C0    LDA   $C089,X
0912-   BD 8E C0    LDA   $C08E,X

; ($F6) points to a data table used by
; the nibble check (see below).
0915-   A9 A5       LDA   #$A5
0917-   85 F6       STA   $F6
0919-   A9 09       LDA   #$09
091B-   85 F7       STA   $F7

; set up the Death Counter
091D-   A9 80       LDA   #$80
091F-   85 F5       STA   $F5
0921-   C6 F5       DEC   $F5

; if the Death Counter hits zero, fail
0923-   F0 76       BEQ   $099B

; this finds the next address prologue
; ("D5 AA 96") and skips over the
; address field
0925-   20 AD 09    JSR   $09AD

; if that didn't work, fail
0928-   B0 71       BCS   $099B

; loop until we find sector $07 (in
; zero page $F1 after routine at $099B)
092A-   A5 F1       LDA   $F1
092C-   C9 07       CMP   #$07
092E-   D0 F1       BNE   $0921

; here we go
0930-   A0 00       LDY   #$00
0932-   BD 8C C0    LDA   $C08C,X
0935-   10 FB       BPL   $0932
0937-   88          DEY
0938-   F0 61       BEQ   $099B  ; fail

; find $D5
093A-   C9 D5       CMP   #$D5
093C-   D0 F4       BNE   $0932

; find $E7 $E7 $E7
093E-   A0 00       LDY   #$00
0940-   BD 8C C0    LDA   $C08C,X
0943-   10 FB       BPL   $0940
0945-   88          DEY
0946-   F0 53       BEQ   $099B  ; fail
0948-   C9 E7       CMP   #$E7
094A-   D0 F4       BNE   $0940
094C-   BD 8C C0    LDA   $C08C,X
094F-   10 FB       BPL   $094C
0951-   C9 E7       CMP   #$E7
0953-   D0 46       BNE   $099B  ; fail
0955-   BD 8C C0    LDA   $C08C,X
0958-   10 FB       BPL   $0955
095A-   C9 E7       CMP   #$E7
095C-   D0 3D       BNE   $099B  ; fail

; kill some time to get out of sync
; with the "proper" start of nibbles
; (see below)
095E-   BD 8D C0    LDA   $C08D,X
0961-   A0 10       LDY   #$10
0963-   24 06       BIT   $06

; now start looking for nibbles that
; don't really exist (except they do,
; because we're out of sync and reading
; timing bits as data)
0965-   BD 8C C0    LDA   $C08C,X
0968-   10 FB       BPL   $0965
096A-   88          DEY
096B-   F0 2E       BEQ   $099B  ; fail
096D-   C9 EE       CMP   #$EE
096F-   D0 F4       BNE   $0965

; check for nibble sequence stored
; in reverse order at $09A5
0971-   A0 07       LDY   #$07
0973-   BD 8C C0    LDA   $C08C,X
0976-   10 FB       BPL   $0973
0978-   D1 F6       CMP   ($F6),Y
097A-   D0 1F       BNE   $099B  ; fail
097C-   88          DEY
097D-   10 F4       BPL   $0973

; success path is here -- reuse the
; disk controller ROM routine to read
; the sector that was supposed to be
; at $0900 in the first place, then
; "return" to $0834
097F-   A2 60       LDX   #$60
0981-   8E 01 08    STX   $0801
0984-   A6 2B       LDX   $2B
0986-   A9 0B       LDA   #$0B
0988-   85 3D       STA   $3D
098A-   A9 09       LDA   #$09
098C-   85 27       STA   $27
098E-   A9 08       LDA   #$08
0990-   48          PHA
0991-   A9 34       LDA   #$34
0993-   48          PHA
0994-   A5 49       LDA   $49
0996-   48          PHA
0997-   A9 5B       LDA   #$5B
0999-   48          PHA
099A-   60          RTS

; if zero page $F4 hits 0, the nibble
; check has failed
099B-   C6 F4       DEC   $F4
099D-   D0 03       BNE   $09A2

; reboot on failure
099F-   4C 00 C6    JMP   $C600

; or continue trying
09A2-   4C 1D 09    JMP   $091D

; data table of nibbles
09A5-   FC EE EE FC
09A9-   E7 EE FC E7

The first two instructions at $0900 are
necessary, but after that I can jump
immediately to the success path at
$097F.

                   ~

               Chapter 5
 In Which We Remove All Traces Of Copy
Protection Using An Automated Tool That
   I Wrote For Just Such An Occasion


[S6,D1=demuffin'd copy]
[S5,D1=my work disk]

]PR#5
...
]BRUN PDP

T00,S0E,$04 change A9008D to 4C7F09

]PR#6
...works...

Disks 2-5 are unprotected.

Quod erat liberand one more thing...

                   ~

               Epilogue
     In Which It's All Just, Like,
            1s And 0s, Man


$E7 $E7 $E7 $E7. What would that nibble
sequence look like on disk? The answer
is, "It depends." $E7 in hexadecimal is
11100111 in binary, so here is the
simplest possible answer:

   |--E7--||--E7--||--E7--||--E7--|
   11100111111001111110011111100111

But wait. Every nibble read from disk
must have its high bit set. In theory,
you could insert one or two "0" bits
after any of those nibbles. (Two is the
maximum due to hardware limitations.)
These extra "0" bits would be swallowed
by the standard "wait for data latch to
have its high bit set" loop:

  :1   LDA $C08C,X
       BPL :1

Consider the following bitstream:

  |--E7--| |--E7--|  |--E7--||--E7--|
  11100111011100111001110011111100111
          ^        ^^
       (extra)   (extra)

The first $E7 has one extra "0" bit
after it, and the second $E7 has two
extra "0" bits after it. Totally legal,
works on any Apple II computer and any
floppy drive. A "LDA $C08C,X; BPL" loop
would still interpret this bitstream as
a sequence of four $E7 nibbles. Each of
the extra "0" bits appear after we've
just read a nibble and we're waiting
for the high bit to be set again.

Now, what if we miss the first few bits
of this bitstream, then start looking?
The disk is always spinning, whether
we're reading from it or not. If we
waste too much time doing something
other than reading, we'll literally
miss some bits as the disk spins by.
This is why the timing of low-level
RWTS code is so critical.

Let's say we waste 12 CPU cycles before
we start reading this bitstream. Each
bit takes 4 CPU cycles to go by, so
after 12 cycles, we would have missed
the first 3 bits (marked with an X).

            (normal start)

  |--E7--| |--E7--|  |--E7--||--E7--|
  11100111011100111001110011111100111
  XXX  |--EE--| |--E7--|  |--FC--|

           (delayed start)

Ah! It's interpreted as a completely
different nibble sequence if you delay
just a few CPU cycles before you start
reading. Also note that some of those
"extra" bits are no longer being
ignored; now they're being interpreted
as data, as part of the nibbles that
are being returned to the higher level
code. Meanwhile, other bits that were
part of the $E7 nibbles are now being
swallowed.

Now, let's go back to the first stream,
which had no extra bits between the
nibbles, and see what happens when we
waste those same 12 CPU cycles.

           (normal start)

   |--E7--||--E7--||--E7--||--E7--|
   11100111111001111110011111100111
   XXX  |--FC--||--FC--||--FC--|

          (delayed start)

After skipping the first three bits,
the stream is interpreted as a series
of $FC $FC $FC repeating endlessly --
not $EE $E7 $FC like the other stream.

Here's the kicker: generic bit copiers
didn't preserve these extra "0" bits
between nibbles. By "desynchronizing"
(wasting just the right number of CPU
cycles at just the right time), then
interpreting the bits on the disk in
mid-stream, developers could determine
at runtime whether you had an original
disk.

Here is the complete "E7 bitstream,"
annotated to show both the synchronized
and desynchronized nibble sequences.

 |--E7--| |--E7--|  |--E7--||--E7--|
 111001110111001110011100111111001110
 XXX  |--EE--| |--E7--|  |--FC--||--E

 |--E7--|  |--E7--||--E7--| |--E7--|
 111001110011100111111001110111001110
 E--| |--E7--|  |--FC--||--EE--| |--E

 |--E7--||--E7--|
 1110011111100111
 E--| |--FC--|

Quod erat liberandum.

---------------------------------------
A 4am crack                     No. 597
------------------EOF------------------
